﻿
#include "RoomMgr.h"
#include "Active/ActiveCharacterMgr.h"
#include "CenterService.h"
#include "RelationMgr/RelationMgr.h"
#include "Duplicate/CenterDuplicateMgr.h"
#include "Common/Utility/ServerTime.h"
#include "Team/TeamManager.h"
#include "AccountMgr/CenterAccountMgr.h"

RoomMgr::RoomMgr() :m_rooPool(nullptr), m_roomUID(1000)
{
	m_mapRoom.clear();
	m_charRoom.clear();
	m_charAuto.clear();
	m_dupRoom.clear();
}

RoomMgr::~RoomMgr()
{

}

bool RoomMgr::Init()
{
	m_rooPool = new ObjectPool<Room>(20, false);
	MMO_ASSERT(m_rooPool);

	g_GetActiveCharacterMgr()->AddCharacterObserver(this);

	return true;
}

void RoomMgr::UnInit()
{
	g_GetActiveCharacterMgr()->RemoveCharacterObserver(this);

	RoomMap::iterator iter = m_mapRoom.begin();
	for (; iter != m_mapRoom.end(); ++iter)
	{
		Room *room = iter->second;
		if (nullptr != room)
		{
			room->uninit();
			FreeRoomObj(room);
		}
	}
	m_mapRoom.clear();
	m_charRoom.clear();
	m_roomUID = 0;
	m_charAuto.clear();
	m_dupRoom.clear();

	MMO_DELETE(m_rooPool);
}

//生成room对象
Room *RoomMgr::MakeRoomObj()
{
	if (nullptr != m_rooPool)
	{
		return m_rooPool->MallocObj();
	}
	return nullptr;
}
//释放room对象
void RoomMgr::FreeRoomObj(Room *pRoom)
{
	m_rooPool->FreeObj(pRoom);
}
//回收房间
void RoomMgr::recycleRoom(Room *room)
{
	if (nullptr != room)
	{
		uint32_t roomId = room->roomId();
		uint32_t dupId = room->dupId();
		RoomMap::iterator iter = m_mapRoom.find(roomId);
		if (iter != m_mapRoom.end())
		{
			m_mapRoom.erase(iter);
		}
		room->uninit();
		FreeRoomObj(room);
		//
		delDupRoom(dupId, roomId);
	}
}


//角色登陆
void RoomMgr::onCharacterLogin(ActiveCharacter *pOnlineCharacter)
{
	_UNUSE(pOnlineCharacter);
	/*uint32_t charRoomId = 0;
	uint32_t roomOwner = 0;
	CharIDType charId = pOnlineCharacter->GetCharID();
	uint32_t roomId = getCharRoom(charId);
	Room *room = getRoom(roomId);
	if (nullptr != room)
	{
		charRoomId = roomId;
		roomOwner = room->roomOwner();
	}

	notifyCharRoom(charId, charRoomId, roomOwner);*/
}
//角色登出
void RoomMgr::onCharacterLogout(ActiveCharacter *pOnlineCharacter)
{
	CharIDType charId = pOnlineCharacter->GetCharID();
	logoutCheck(charId);
}
//角色更新
void RoomMgr::onCharacterUpdate(ActiveCharacter *pOnlineCharacter)
{
	_UNUSE(pOnlineCharacter);
}
//删除角色
void RoomMgr::onCharacterDel(OfflineCharacterData *pOffLineCharacter)
{
	_UNUSE(pOffLineCharacter);
}
//断开连接
void RoomMgr::onCharacterDisconnect(ActiveCharacter *pOnlineCharacter)
{
	_UNUSE(pOnlineCharacter);
}

//添加副本房间
void RoomMgr::addDupRoom(uint32_t dupId, uint32_t roomId)
{
	MAP_UINT32_SET_UINT32::iterator iter = m_dupRoom.find(dupId);
	if (iter != m_dupRoom.end())
	{
		iter->second.insert(roomId);
	}
	else
	{
		SET_UINT32 setRoom;
		setRoom.insert(roomId);
		m_dupRoom[dupId] = setRoom;
	}
}
//删除副本房间
void RoomMgr::delDupRoom(uint32_t dupId, uint32_t roomId)
{
	MAP_UINT32_SET_UINT32::iterator iter = m_dupRoom.find(dupId);
	if (iter != m_dupRoom.end())
	{
		iter->second.erase(roomId);
	}
}
//获取副本房间
const SET_UINT32 *RoomMgr::getDupRoom(uint32_t dupId)
{
	MAP_UINT32_SET_UINT32::iterator iter = m_dupRoom.find(dupId);
	return (iter != m_dupRoom.end()) ? &iter->second : nullptr;
}
//获取副本房间
void RoomMgr::getDupRoom(uint32_t dupId,SET_UINT32 &setDupRoom)
{
	setDupRoom.clear();
	MAP_UINT32_SET_UINT32::iterator iter = m_dupRoom.find(dupId);
	if (iter != m_dupRoom.end())
	{
		SET_UINT32 &setRoom = iter->second;
		SET_UINT32::iterator iterRoom = setRoom.begin();
		for (; iterRoom != setRoom.end(); ++iterRoom)
		{
			Room *room = getRoom((*iterRoom));
			if (nullptr != room && ERoomState_None == room->state())
			{
				setDupRoom.insert((*iterRoom));
			}
		}
	}
}

//解散副本
void RoomMgr::dismissRoom(uint32_t roomId, int8_t notifyDup /*= 1*/)
{
	SET_UINT64 setMember;
	setMember.clear();
	Room *room = getRoom(roomId);
	if (nullptr != room)
	{
		RoomMemberMap &mapMember = room->allMember();
		RoomMemberMap::iterator iter = mapMember.begin();
		for (; iter != mapMember.end(); ++iter)
		{
			setMember.insert(iter->first);			
		}
	}
	auto iterSet = setMember.begin();
	for (; iterSet != setMember.end(); ++iterSet)
	{
		CharIDType charId = (*iterSet);
		//离开房间
		leaveRoom(charId, notifyDup);
	}
}

//获取房间
Room *RoomMgr::getRoom(uint32_t roomId)
{
	RoomMap::iterator iter = m_mapRoom.find(roomId);
	return (iter != m_mapRoom.end()) ? iter->second : nullptr;
}

//获取房间副本
uint32_t RoomMgr::getRoomDup(uint32_t roomId)
{
	Room *room = getRoom(roomId);
	if (nullptr != room)
	{
		return room->dupId();
	}
	return 0;
}

//获取玩家所在房间id
uint32_t RoomMgr::getCharRoom(CharIDType charId)
{
	auto iter = m_charRoom.find(charId);
	return (iter != m_charRoom.end()) ? iter->second : 0;
}

//删除玩家所在房间id
void RoomMgr::delCharRoom(CharIDType charId)
{
	m_charRoom.erase(charId);
}
//增加玩家所在房间id
void RoomMgr::addCharRoom(CharIDType charId, uint32_t roomId)
{
	m_charRoom[charId] = roomId;
}

//能扣离开房间
int32_t RoomMgr::canLeaveRoom(CharIDType charId)
{
	uint32_t roomId = getCharRoom(charId);
	Room *room = getRoom(roomId);
	if (nullptr == room)
	{
		return RET_ROOM_NOT_EXIST;
	}
	RoomMember *pmember = room->getMember(charId);
	if (nullptr == pmember)
	{
		return RET_ROOM_NOT_ROOM_MEMBER;
	}
	//判断房间状态，在副本中是不允许有房间操作的
	if (g_GetCenterDuplicateMgr()->isCharInDup(charId))
	{
		return RET_DUPLICATE_ALREAY_IN;
	}

	return RET_SUCCESS;
}

bool RoomMgr::leaveRoom(CharIDType charId, int8_t notifyDup /*= 1*/)
{
	CharIDType newOwner = 0;
	CharIDType changeCid = 0;
	Room *room = leaveRoomEx(charId, newOwner, changeCid);
	if (nullptr != room)
	{
		//通知场景服更新玩家房间
		notifyCharRoom(charId, 0, 0, notifyDup);

		Room_NotifyLeave notifyLeaveRsp;
		notifyLeaveRsp.set_cid(charId);

		//判断房间人数
		if (0 == room->memberNum())
		{
			//通知离开
			g_GetCenterService()->SendDataToClient(charId, (uint16_t)EMODULE_ID_ROOM, (uint16_t)LOGIC_TO_CLIENT_ROOM_NOTIFY_LEAVE, &notifyLeaveRsp);
			//回收房间
			recycleRoom(room);
		}
		else if (newOwner > 0)
		{
			//通知逻辑服更新所有房员房间
			notifyAllCharRoom(room->roomId(), notifyDup);
			//通知其房员，有房员离开
			broadRoom(room->roomId(), EMODULE_ID_ROOM, LOGIC_TO_CLIENT_ROOM_NOTIFY_LEAVE, &notifyLeaveRsp,charId);


			//离开的是房主，有房员成为新房主，通知所有人新房主信息更新
			Room_NotifyUpdate notifyUpate;
			RoomDetailProto *protoDetail = notifyUpate.mutable_update();
			if (nullptr != protoDetail)
			{
				RoomAllMemberProto *protoMember = protoDetail->mutable_member();
				if (nullptr != protoMember)
				{
					RoomMemberProto *proto = protoMember->add_member();
					room->getMemberProto(proto, newOwner);
					//如果重选房主的时候，有房员位置有改变，需要更新
					if (changeCid > 0)
					{
						RoomMemberProto *protoA = protoMember->add_member();
						room->getMemberProto(protoA, changeCid);
					}
					broadRoom(room->roomId(), EMODULE_ID_ROOM, LOGIC_TO_CLIENT_ROOM_NOTIFY_UPDATE, &notifyUpate);
				}
			}
			
		}
		else
		{
			//通知其他房员，成员离开
			//通知其房员，有房员离开
			broadRoom(room->roomId(), EMODULE_ID_ROOM, LOGIC_TO_CLIENT_ROOM_NOTIFY_LEAVE, &notifyLeaveRsp, charId);
		}
		return true;
	}
	return false;
}
//离开房间
Room* RoomMgr::leaveRoomEx(CharIDType charId, CharIDType &newOwner,CharIDType &changeCid)
{
	newOwner = 0;
	uint32_t roomId = getCharRoom(charId);
	Room *room = getRoom(roomId);
	if (nullptr == room)
	{
		return nullptr;
	}
	RoomMember *pmember = room->getMember(charId);
	if (nullptr == pmember)
	{
		return nullptr;
	}
	bool needSel = false;
	if (ERoomMemberType_Owner == pmember->type)
	{
		needSel = true;
	}
	room->delMember(charId);
	room->delInvite(charId);
	delCharRoom(charId);
	//如果离开的是房主,重新选房主
	if (needSel)
	{
		changeCid = room->selectOwner();
		newOwner = room->roomOwner();
	}

	return room;
}

//能否邀请好友加入房间
int32_t RoomMgr::canInviteRoom(CharIDType charId, uint32_t roomId, CharIDType frdCid)
{
	Room *room = getRoom(roomId);
	if (nullptr == room)
	{
		//房间不存在
		return RET_ROOM_NOT_EXIST;
	}
	if (room->memberNum() >= ROOM_MAX_MEMBER_COUNT)
	{
		//人数已满
		return RET_ROOM_ALREADY_MAX_NUM;
	}
	RoomMember *pmember = room->getMember(charId);
	if (nullptr == pmember)
	{
		//
		return RET_ROOM_NOT_JOIN;
	}
	if (ERoomMemberType_Owner != pmember->type)
	{
		//不是房主
		return RET_ROOM_NOT_ROOM_OWNER;
	}
	if (room->hasInvite(frdCid))
	{
		//已经邀请过了
		return RET_ROOM_ALREAY_INVITE;
	}

	if (ERoomState_None != room->state())
	{
		//房间状态不允许邀请
		return RET_ROOM_STATE_NOT_ALLOW_INVITE;
	}

	uint32_t frdRoomId = getCharRoom(frdCid);
	if (frdRoomId > 0)
	{
		if (frdRoomId != roomId)
		{
			//已经加入其它房间
			return RET_ROOM_ALREADY_JOIN_OTHER;
		}
		else
		{
			//已经加入房间
			return RET_ROOM_ALREADY_JOIN;
		}
	}


	//这里需要判断好友是否在队伍中
	if (g_GetTeamMgr()->GetTeamId(frdCid) > 0)
	{
		return RET_TEAM_OTHER_ALREADY_JOIN;
	}

	//这里需要判断房间状态 在副本中是不允许有房间操作的
	if (g_GetCenterDuplicateMgr()->isCharInDup(frdCid))
	{
		return RET_DUPLICATE_OTHER_ALREADY_IN;
	}

	//是否是好友关系
	if (!g_GetRelationMgr()->IsFriendRelation(charId,frdCid))
	{
		//非好友
		return RET_RELATION_NOT_FRIENDS;
	}

	return RET_SUCCESS;
}

//是否能踢出玩家
int32_t RoomMgr::canKickRoom(CharIDType charId, CharIDType kickCid)
{
	uint32_t roomId = getCharRoom(charId);
	Room *room = getRoom(roomId);
	if (nullptr == room)
	{
		return RET_ROOM_NOT_EXIST;
	}
	RoomMember *pmember = room->getMember(charId);
	if (nullptr == pmember)
	{
		return RET_ROOM_NOT_ROOM_MEMBER;
	}
	if (ERoomMemberType_Owner != pmember->type)
	{
		return RET_ROOM_NOT_ROOM_OWNER;
	}
	RoomMember *pkickmember = room->getMember(kickCid);
	if (nullptr == pmember)
	{
		return RET_ROOM_OTHER_NOT_JOIN;
	}
	if (ERoomMemberType_Owner == pkickmember->type)
	{
		return RET_ROOM_NOT_KICK_OWNER;
	}

	//房间状态判断
	if (ERoomState_None != room->state())
	{
		return RET_ROOM_STATE_NOT_KICK;
	}

	//状态判断，副本中无法进行房间操作
	if (g_GetCenterDuplicateMgr()->isCharInDup(charId))
	{
		return RET_DUPLICATE_ALREAY_IN;
	}


	return RET_SUCCESS;
}

//踢出玩家
Room *RoomMgr::kickRoom(CharIDType charId, CharIDType kickCid)
{
	uint32_t roomId = getCharRoom(charId);
	Room *room = getRoom(roomId);
	if (nullptr == room)
	{
		return nullptr;
	}

	//通知场景服更新玩家房间
	g_GetRoomMgr()->notifyCharRoom(kickCid, 0, 0);
	//通知房间其他成员，有成员被踢出
	Room_NotifyMemberKick notify;
	notify.set_kick(kickCid);
	g_GetRoomMgr()->broadRoom(room->roomId(), EMODULE_ID_ROOM, LOGIC_TO_CLIENT_ROOM_NOTIFY_MEMBER_KICK, &notify);

	//
	room->delMember(kickCid);
	room->delInvite(kickCid);
	delCharRoom(kickCid);

	return room;
}
//获取自动加入时间
uint64_t RoomMgr::getAutoJoinCd(CharIDType charId)
{
	auto iter = m_charAuto.find(charId);
	return (iter != m_charAuto.end()) ? iter->second : 0;
}
//更新自动加入时间
void RoomMgr::updateAutoJoinCd(CharIDType charId)
{
	m_charAuto[charId] = g_GetGlobalServerTime()->UnixSec();
}
//是否在自动加入的CD中
bool RoomMgr::isAutoJoinCd(CharIDType charId)
{
	uint64_t nowSec = g_GetGlobalServerTime()->UnixSec();
	uint32_t joinSec = getAutoJoinCd(charId);
	if (nowSec - joinSec < ROOM_AUTO_JOIN_CD)
	{
		return true;
	}
	return false;
}

//随机一个房间
Room *RoomMgr::getRandRoom(CharIDType charId, uint32_t dupId)
{
	_UNUSE(charId);
	RoomMap::iterator iter = m_mapRoom.begin();
	for (; iter != m_mapRoom.end(); ++iter)
	{
		Room *room = iter->second;
		if (room->dupId() != dupId)
		{
			continue;
		}
		if (room->state() != ERoomState_None)
		{
			continue;
		}
		if (room->hasPwd())
		{
			continue;
		}
		if (room->memberNum() >= ROOM_MAX_MEMBER_COUNT)
		{
			continue;
		}
		return room;
	}
	return nullptr;
}

//玩家下线检查
void RoomMgr::logoutCheck(CharIDType charId)
{
	//玩家下线，检查房间所有成员，如果都下线，解散房间
	//如果下线玩家是房主，则重新选一个新房主
	uint32_t roomId = getCharRoom(charId);
	Room *proom = getRoom(roomId);
	if (nullptr == proom)
	{
		return;
	}
	//先检查是否所有房员都下线了
	bool all_logout = true;
	SET_UINT64 setAllChar;
	setAllChar.clear();
	RoomMemberMap &allMap = proom->allMember();
	RoomMemberMap::iterator iterMem = allMap.begin();
	for (; iterMem != allMap.end(); ++iterMem)
	{
		setAllChar.insert(iterMem->first);
		if (charId == iterMem->second.cid)
		{
			continue;
		}
		ActiveCharacter *pOnline = g_GetActiveCharacterMgr()->GetOnlineCharacter(iterMem->first);
		if (nullptr != pOnline)
		{
			all_logout = false;
			break;
		}
	}
	if (all_logout) //所有成员都下线了，解散
	{
		CharIDType newOwner = 0;
		CharIDType changeCid = 0;
		SET_UINT64::iterator iter = setAllChar.begin();
		for (; iter != setAllChar.end(); ++iter)
		{
			leaveRoomEx((*iter), newOwner, changeCid);
		}
		recycleRoom(proom);

		return;
	}

	//如果是房主离开,重新选房主
	if (charId == proom->roomOwner())
	{
		//重新选房主
		CharIDType changeMemCid = proom->selectOwner(charId);
		//通知逻辑服更新所有房员房间
		SET_UINT64::iterator iter = setAllChar.begin();
		for (; iter != setAllChar.end(); ++iter)
		{
			if (charId == (*iter)) //顾虑掉当前下线的角色
			{
				continue;
			}
			//通知逻辑服房间信息
			notifyCharRoom((*iter), roomId, proom->roomOwner());
		}

		//离开的是房主，有房员成为新房主，通知所有人新房主信息更新， 房主变为房员，通知所有人
		Room_NotifyUpdate notifyUpate;
		RoomDetailProto *protoDetail = notifyUpate.mutable_update();
		if (nullptr != protoDetail)
		{
			RoomAllMemberProto *protoMember = protoDetail->mutable_member();
			if (nullptr != protoMember)
			{
				RoomMemberProto *proto = protoMember->add_member();
				RoomMemberProto *protoA = protoMember->add_member();
				proom->getMemberProto(proto, proom->roomOwner());
				proom->getMemberProto(protoA, charId);
				if (changeMemCid > 0 && changeMemCid != charId)
				{
					//与房主互换位置的房员不是当前下线的玩家
					RoomMemberProto *protoB = protoMember->add_member();
					proom->getMemberProto(protoB, changeMemCid);
				}
				broadRoom(roomId, EMODULE_ID_ROOM, LOGIC_TO_CLIENT_ROOM_NOTIFY_UPDATE, &notifyUpate,charId);
			}
		}
	}
	//
	if (ERoomState_Success != proom->state())
	{
		//房员下线，如果房间已经是 进入副本成功状态，保留房间信息,不做处理
		//否则，房员移出房间
		leaveRoom(charId);
	}
}
//进入成功
Room *RoomMgr::enterSuccess(uint32_t roomId)
{
	Room *room = getRoom(roomId);
	if (nullptr != room)
	{
		room->state(ERoomState_Success);
	}
	return room;
}
//重置房间状态
Room *RoomMgr::resetState(uint32_t roomId)
{
	Room *room = getRoom(roomId);
	if (nullptr != room)
	{
		room->state(ERoomState_None);
	}
	return room;
}
//开始战斗
Room* RoomMgr::startFight(uint32_t roomId,uint32_t sceneId)
{
	Room *room = getRoom(roomId);
	if (nullptr != room)
	{
		room->state(ERoomState_Create);
		room->dupSceneId(sceneId);
	}
	return room;
}
//开始倒计时
Room *RoomMgr::startCountDown(uint32_t roomId)
{
	Room *room = getRoom(roomId);
	if (nullptr != room)
	{
		if (room->startCountDown())
		{
			room->state(ERoomState_CountDown);
			//通知其他房员，开始倒计时
			Room_NotifyCountDown notify;
			broadRoom(roomId, EMODULE_ID_ROOM, LOGIC_TO_CLIENT_ROOM_NOTIFY_COUNTDOWN, &notify);
		}
		else
		{
			LogErrFmtPrint("[center] RoomMgr::startCountDown....room exists but room->startCountDown() failed...roomId:%u ", roomId);
			return nullptr;
		}
	}
	return room;
}
//结束倒计时
void RoomMgr::endCountDown(Room *room)
{
	if (nullptr == room)
	{
		return;
	}
	//结束倒计时，通知进入副本，设置为进入副本状态
	room->state(ERoomState_Enter);
	g_GetCenterDuplicateMgr()->notifyEnterDup(room->dupSceneId());

}
//能否开始战斗
int32_t RoomMgr::canStartFight(CharIDType charId, uint32_t roomId)
{
	Room *room = getRoom(roomId);
	if (nullptr == room)
	{
		return RET_ROOM_NOT_JOIN;
	}
	if (room->getMember(charId) == nullptr)
	{
		return RET_ROOM_NOT_ROOM_MEMBER;
	}
	if (room->roomOwner() != charId)
	{
		return RET_ROOM_NOT_OWNER;
	}
	if (room->state() != ERoomState_None)
	{
		return RET_ROOM_STATE_NOT_START_FIGHT;
	}

	//检查房员，必须都在线，没有断开连接
	RoomMemberMap &memMap = room->allMember();
	/*if (memMap.size() < ROOM_MAX_MEMBER_COUNT)
	{
		return RET_ROOM_MEMBER_COUNT_LACK;
	}*/
	RoomMemberMap::iterator iter = memMap.begin();
	for (; iter != memMap.end(); ++iter)
	{
		CharIDType charid = iter->first;
		ActiveCharacter *pActiveChar = g_GetActiveCharacterMgr()->GetOnlineCharacter(charid);
		if (nullptr == pActiveChar)
		{
			//不在线
			return RET_ROOM_MEMBER_NOT_ONLINE;
		}
		else if (pActiveChar->GetDisconnectFlag())
		{
			//已经断开连接
			return RET_ROOM_MEMBER_DISCONNECT;
		}
		else if (g_GetCenterDuplicateMgr()->isCharInDup(charid))
		{
			return RET_ROOM_MEMBER_ALREADY_IN_DUP;
		}
		else if (g_GetTeamMgr()->GetTeamId(charid) > 0)
		{
			if (charId == charid)
			{
				return RET_TEAM_ALREADY_JOIN;
			}
			return  RET_ROOM_MEMBER_IN_TEAM;
		}
		else if (g_GetCenterDuplicateMgr()->inQueue(charId))
		{
			return RET_DUPLICATE_ALREADY_IN_QUEUE;
		}

	}

	return RET_SUCCESS;
}

//创建房间
Room* RoomMgr::createRoom(CharIDType charId, uint32_t dupId, int8_t *pwd /*= nullptr*/)
{
	Room *room = MakeRoomObj();
	if (nullptr == room)
	{
		return nullptr;
	}
	uint32_t roomUID = generalRoomUID();
	if (!room->init(roomUID, dupId, charId, pwd))
	{
		FreeRoomObj(room);
		room = nullptr;
		return nullptr;
	}
	room->addMember(charId, ERoomMemberType_Owner);

	m_mapRoom[roomUID] = room;
	addCharRoom(charId, roomUID);
	addDupRoom(dupId, roomUID);

	//通知场景服更新玩家房间
	notifyCharRoom(charId, roomUID, room->roomOwner());

	return room;
}

//玩家是否可以创建房间
int32_t RoomMgr::canCreateRoom(CharIDType charId)
{
	if (getCharRoom(charId) > 0)
	{
		//已经加入房间
		return RET_ROOM_ALREADY_JOIN;
	}
	//这里判断是否已经加入队伍
	if (g_GetTeamMgr()->GetTeamId(charId))
	{
		return RET_TEAM_ALREADY_JOIN;
	}
	if (g_GetCenterDuplicateMgr()->isCharInDup(charId))
	{
		return RET_DUPLICATE_ALREAY_IN;
	}

	return RET_SUCCESS;
}
//玩家是否可以设置密码
int32_t RoomMgr::canSetPwd(CharIDType charId)
{
	uint32_t roomId = getCharRoom(charId);
	Room *room = getRoom(roomId);
	if (nullptr == room)
	{
		return RET_ROOM_NOT_JOIN;
	}
	if (nullptr == room->getMember(charId))
	{
		//不是房员
		return RET_ROOM_NOT_ROOM_MEMBER;
	}
	if (room->roomOwner() != charId)
	{
		//不是房主
		return RET_ROOM_NOT_ROOM_OWNER;
	}

	//这里需要判断房间状态 在副本中是不允许有房间操作的


	return RET_SUCCESS;
}


//玩家能否加入房间
int32_t RoomMgr::canJoinRoom(CharIDType charId, uint32_t roomId,uint32_t dupId, int8_t *pwd /*= nullptr*/)
{
	Room *room = getRoom(roomId);
	if (nullptr == room)
	{
		//房间不存在
		return RET_ROOM_NOT_EXIST;
	}
	if (room->memberNum() >= ROOM_MAX_MEMBER_COUNT)
	{
		//人数已满
		return RET_ROOM_ALREADY_MAX_NUM;
	}

	if (room->state() != ERoomState_None)
	{
		return RET_ROOM_STATE_CAN_NOT_JOIN; //房间状态不允许加入
	}

	if (room->dupId() != dupId)
	{
		//副本ID不一样
		LogErrFmtPrint("[center] RoomMgr::canJoinRoom....room->dupId():%u != dupId:%u", room->dupId(),dupId);
		return RET_ROOM_CAN_NOT_JOIN;
	}
	//这里需要判断是否在队伍中
	if (g_GetTeamMgr()->GetTeamId(charId) > 0)
	{
		return RET_TEAM_ALREADY_JOIN;
	}

	//这里需要判断房间状态 在副本中是不允许有房间操作的
	if (g_GetCenterDuplicateMgr()->isCharInDup(charId))
	{
		return RET_DUPLICATE_ALREAY_IN;
	}

	uint32_t charRoomId = getCharRoom(charId);
	if (charRoomId > 0)
	{
		if (charRoomId != roomId)
		{
			//已经加入其它房间
			return RET_ROOM_ALREADY_JOIN_OTHER;
		}
		else
		{
			//已经加入房间
			return RET_ROOM_ALREADY_JOIN;
		}
	}

	//判断密码
	if (room->hasPwd())
	{
		if (nullptr != pwd)
		{
			if (!room->samePwd(pwd))
			{
				//密码错误
				return RET_ROOM_PWD_ERROR;
			}
		}
		else
		{
			//密码错误
			return RET_ROOM_PWD_ERROR;
		}
	}
	
	return RET_SUCCESS;
}

//加入房间
Room* RoomMgr::joinRoom(CharIDType charId, uint32_t roomId, int8_t charType)
{
	Room *room = getRoom(roomId);
	if (nullptr == room)
	{
		return nullptr;
	}
	room->addMember(charId, charType);
	room->delInvite(charId);
	addCharRoom(charId, roomId);

	//通知其他房员有新房员加入
	Room_NotifyJoin notify;
	RoomMemberProto *proto = notify.mutable_join();
	if (nullptr != proto)
	{
		room->getMemberProto(proto, charId);
		broadRoom(roomId, EMODULE_ID_ROOM, LOGIC_TO_CLIENT_ROOM_NOTIFY_JOIN, &notify, charId);
	}
	else
	{
		LogErrFmtPrint("RoomMgr::joinRoom...nullptr == proto cid:%lu,roomid:%u,type:%d ", charId, roomId, charType);
	}
	//通知场景服更新玩家房间
	notifyCharRoom(charId, roomId, room->roomOwner());

	return room;
}

//拒绝加入
void RoomMgr::refuseJoin(CharIDType charId, uint32_t roomId)
{
	Room *room = getRoom(roomId);
	if (nullptr == room)
	{
		return;
	}
	room->delInvite(charId);
}

//通知房间其他成员有新成员加入
void RoomMgr::broadRoom(uint32_t roomId, uint16_t moduleId, uint16_t commandId, ProtoBufBase *pbuf, CharIDType exceptId /*= 0*/)
{
	Room *room = getRoom(roomId);
	if (nullptr == room)
	{
		return;
	}	
	RoomMemberMap &allMemberMap = room->allMember();
	RoomMemberMap::iterator iter = allMemberMap.begin();
	for (; iter != allMemberMap.end(); ++iter)
	{
		if (exceptId == iter->first)
		{
			continue;
		}
		g_GetCenterService()->SendDataToClient(iter->first, moduleId, commandId, pbuf);
	}

}
//通知逻辑服玩家房间更新
void RoomMgr::notifyCharRoom(CharIDType charId, uint32_t roomId, CharIDType roomOwnerId, int8_t notifyDup /*= 1*/)
{
	CLRoom_CharRoomNotify notify;
	notify.set_charid(charId);
	notify.set_roomid(roomId);
	notify.set_is_owner((int32_t)(roomOwnerId == charId));
	notify.set_notify_dup(notifyDup);
	if (!g_GetCenterService()->SendDataToLogicByCharID(charId, EMODULE_ID_ROOM, CENTER_TO_LOGIC_ROOM_CHAR_ROOM_NOTIFY, &notify))
	{
		LogErrFmtPrint("[center] RoomMgr::notifyCharRoom....SendDataToLogicByCharID failed.... charid:%llu, roomid:%u, ownerid:%llu ", charId, roomId, roomOwnerId);
	}
}

//通知逻辑服更新所有玩家房间
void RoomMgr::notifyAllCharRoom(uint32_t roomId, int8_t notifyDup /*= 1*/)
{
	Room *room = getRoom(roomId);
	if (nullptr != room)
	{
		CharIDType roomOwnerId = room->roomOwner();
		CLRoom_CharRoomNotify notify;
		notify.set_roomid(roomId);
		notify.set_notify_dup(notifyDup);
		RoomMemberMap &allMemberMap = room->allMember();
		RoomMemberMap::iterator iter = allMemberMap.begin();
		for (; iter != allMemberMap.end(); ++iter)
		{
			CharIDType charId = iter->first;
			notify.set_charid(charId);
			notify.set_is_owner((int32_t)(roomOwnerId == charId));
			if (!g_GetCenterService()->SendDataToLogicByCharID(charId, EMODULE_ID_ROOM, CENTER_TO_LOGIC_ROOM_CHAR_ROOM_NOTIFY, &notify))
			{
				LogErrFmtPrint("[center] RoomMgr::notifyAllCharRoom....SendDataToLogicByCharID failed....charid:%llu, roomid:%u, ownerid:%llu ", charId, roomId, roomOwnerId);
			}
		}
	}
}


void RoomMgr::loginSyncData(CharIDType charId, CharLoginSyncCenterData *protoLoginSync)	//登录同步
{
	uint32_t roomId = getCharRoom(charId);
	Room *pRoom = getRoom(roomId);
	if (nullptr != pRoom)
	{
		protoLoginSync->set_room_id(pRoom->roomId());
		protoLoginSync->set_is_owner((int32_t)(charId == pRoom->roomOwner()) );
	}
	else
	{
		protoLoginSync->set_room_id(0);
		protoLoginSync->set_is_owner(0);
	}
}